package com.kexio.auth.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;

/**
 * 限流注解
 * 
 * 标注在控制器方法上，用于对接口进行访问频率限制，
 * 防止恶意请求和系统过载。
 * 
 * 支持多种限流策略：
 * - 基于用户的限流
 * - 基于IP的限流  
 * - 基于接口的全局限流
 * - 滑动窗口算法
 * - 令牌桶算法
 * 
 * <pre>
 * &#64;PostMapping("/send-sms")
 * &#64;RateLimit(key = "sms", count = 5, time = 1, timeUnit = TimeUnit.MINUTES, limitType = LimitType.USER)
 * public Result&lt;Void&gt; sendSms(&#64;RequestBody SendSmsRequest request) {
 *     smsService.sendVerificationCode(request.getPhone());
 *     return Result.success();
 * }
 * 
 * &#64;PostMapping("/upload")
 * &#64;RateLimit(count = 10, time = 1, timeUnit = TimeUnit.SECONDS)
 * public Result&lt;String&gt; upload(&#64;RequestParam("file") MultipartFile file) {
 *     return fileService.upload(file);
 * }
 * </pre>
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
    
    /**
     * 限流类型枚举
     */
    enum LimitType {
        /**
         * 根据用户限流 - 每个用户独立计算限流次数
         */
        USER,
        
        /**
         * 根据IP限流 - 每个IP独立计算限流次数
         */
        IP,
        
        /**
         * 全局限流 - 所有请求共享限流次数
         */
        GLOBAL,
        
        /**
         * 自定义限流 - 根据自定义key限流
         */
        CUSTOM
    }
    
    /**
     * 限流算法枚举
     */
    enum Algorithm {
        /**
         * 滑动窗口算法 - 精确控制时间窗口内的请求数量
         */
        SLIDING_WINDOW,
        
        /**
         * 令牌桶算法 - 允许突发流量，平滑限流
         */
        TOKEN_BUCKET,
        
        /**
         * 固定窗口算法 - 简单的计数器实现
         */
        FIXED_WINDOW
    }
    
    /**
     * 限流key
     * 
     * 用于区分不同的限流规则，当limitType为CUSTOM时必填
     * 支持SpEL表达式，可以使用方法参数：
     * - key = "'upload:' + #file.originalFilename" 
     * - key = "'api:' + #request.userId"
     * 
     * @return 限流key
     */
    String key() default "";
    
    /**
     * 限流次数
     * 
     * 在指定时间范围内允许的最大请求次数
     * 
     * @return 最大请求次数
     */
    int count();
    
    /**
     * 时间范围
     * 
     * 与timeUnit配合使用，定义限流的时间窗口
     * 
     * @return 时间数值
     */
    long time() default 1;
    
    /**
     * 时间单位
     * 
     * @return 时间单位，默认为分钟
     */
    TimeUnit timeUnit() default TimeUnit.MINUTES;
    
    /**
     * 限流类型
     * 
     * @return 限流类型，默认为用户级限流
     */
    LimitType limitType() default LimitType.USER;
    
    /**
     * 限流算法
     * 
     * @return 限流算法，默认为滑动窗口
     */
    Algorithm algorithm() default Algorithm.SLIDING_WINDOW;
    
    /**
     * 限流失败时的错误消息
     * 
     * @return 错误消息，为空时使用默认消息
     */
    String message() default "访问过于频繁，请稍后再试";
    
    /**
     * 是否启用限流
     * 
     * 可以通过配置动态控制是否启用限流
     * 
     * @return true-启用限流，false-跳过限流检查
     */
    boolean enabled() default true;
}
